package com.gitee.apanlh.util.net.http.log;

import com.gitee.apanlh.exp.HttpStatusException;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.id.IdUtils;
import com.gitee.apanlh.util.log.Log;
import com.gitee.apanlh.util.log.LogLevel;
import com.gitee.apanlh.util.net.http.HttpBody;
import com.gitee.apanlh.util.net.http.HttpRequest;
import com.gitee.apanlh.util.net.http.HttpResponse;
import com.gitee.apanlh.util.net.http.HttpStatus;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;

/**
 * 	HTTP日志输出
 * 	
 * 	@author Pan
 */
public class HttpLog {
	
	/** HTTP链路记录ID */
	private Long traceId;
	/** HTTP请求对象 */
	private HttpRequest httpRequest;
	/** HTTP状态 */ 
	private HttpStatus httpStatus;
	/** 请求日志 */
	private String requestLog;
	/** 响应日志 */
	private String responseLog;
	/** 响应日志状态 */
	private boolean writeResponse = false;
	
	/**	
	 * 	构造函数-加载HTTP请求对象
	 * 	
	 * 	@author Pan
	 * 	@param 	httpRequest	HTTP请求对象
	 */
	public HttpLog(HttpRequest httpRequest) {
		this.httpRequest = httpRequest;
	}

	/**	
	 * 	写入请求日志记录
	 * 	
	 * 	@author Pan
	 */
	public void writeRequest() {
		if (!httpRequest.getConfig().hasWriteRequestBody()) {
			return ;
		}
		if (traceId == null) {
			createTraceId();
		}
		HttpBody body = httpRequest.getBody();
		
		this.requestLog = StringUtils.format("http log type:[request ] id:{}, url:{}, method:{}, headers:{}, body:{}",
			traceId,
			httpRequest.getUrl(),
			httpRequest.getMethod(),
			httpRequest.getHeader(),
			body == null ? null : body.getRequestBody()
		);
		
		Log.write(httpRequest.getConfig().getLogLevel(), this.requestLog);
	}
	
	/**	
	 * 	写入响应日志记录
	 * 	<br>调用{@link HttpResponse#getStr()}记录打印数据
	 * 	<br>调用{@link HttpResponse#getByte()}记录打印数据, 将返回Byte[]类型返回长度
	 * 	<br>调用{@link HttpResponse#getByte()}记录打印数据
	 * 	
	 * 	@author Pan
	 *  @param  <T> 数据类型
	 * 	@param 	t	对象
	 */
	public <T> void writeResponse(T t) {
		if (writeResponse || !httpRequest.getConfig().hasWriteResponseBody()) {
			return ;
		}
		LogLevel logLevel = httpRequest.getConfig().getLogLevel();

		if (t == null) {
			writeResponse = true;
			this.responseLog = StringUtils.format("http log type:[response] id:{}, url:{}, method:{}, body:null",
					traceId,
					httpRequest.getUrl(),
					httpRequest.getMethod()
			);
			Log.write(logLevel, this.responseLog);
			return ;
		}
		if (t instanceof byte[]) {
			writeResponse = true;
			this.responseLog = StringUtils.format("http log type:[response] id:{}, url:{}, method:{}, bodyType:byte[], content-length:{}",
				traceId,
				httpRequest.getUrl(),
				httpRequest.getMethod(),
				ClassConvertUtils.castArrayByte(t).length
			);
			Log.write(logLevel, this.responseLog);
			return ;
		}
		if (t instanceof String) {
			writeResponse = true;
			this.responseLog = StringUtils.format("http log type:[response] id:{}, url:{}, method:{}, body:{}",
				traceId,
				httpRequest.getUrl(),
				httpRequest.getMethod(),
				t
			);
			Log.write(logLevel, this.responseLog);
		}
	}
	
	/**	
	 * 	写入错误响应信息
	 * 	
	 * 	@author Pan
	 * 	@param 	message	异常消息
	 * 	@throws HttpStatusException	http状态异常抛出
	 */
	public void writeError(String message) {
		Log.write(httpRequest.getConfig().getErrorLogLevel(), StringUtils.format(
			"http log type:[response status error] id:{}, url:{}, method:{}, code:{}, msg:{}, body:{}",
			traceId,
			httpRequest.getUrl(),
			httpRequest.getMethod(),
			httpStatus.getCode(),
			httpStatus.getMessage(),
			message)
		);
	}
    
    /**	
     * 	设置-HTTP响应状态对象
     * 	
     * 	@author Pan
     * 	@param 	httpStatus HTTP响应状态对象
     */
    public void setHttpStatus(HttpStatus httpStatus) {
		this.httpStatus = httpStatus;
	}
    
    /**
     * 	设置-链路ID
     * 	<br>只有请求体和返回体同时开启记录日志时才创建
     * 	
     * 	@author Pan
     * 	@param 	id id
     */
    public void setTraceId(Long id) {
		traceId = id;
    }
    
	/**	
	 * 	获取-请求日志
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public String getRequestLog() {
		return this.requestLog;
	}
	
	/**	
	 * 	获取-响应日志
	 * 	
	 * 	@author Pan
	 * 	@return	String
	 */
	public String getResponseLog() {
		return this.responseLog;
	}
	
    /**
     * 	创建链路ID
     * 	<br>只有请求体和返回体同时开启记录日志时才创建
     * 	
     * 	@author Pan
     */
    private void createTraceId() {
		traceId = IdUtils.snowFlakeId(31L, 31L);
    }

	/**	
     * 	创建HTTP日志
     * 	
     * 	@author Pan
     * 	@param 	httpRequest	HTTP请求对象
     * 	@return	HttpLog
     */
    public static HttpLog create(HttpRequest httpRequest) {
    	return new HttpLog(httpRequest);
    }
}
